/** 
 * @Description: 文件描述
 * @Author: 程前
 * @Date: 2024-11-29 17:19:39
 * @LastEditors: 程前
 * @LastEditTime: 2025-02-19 14:34:40
 */

import { Viewer, Color, EllipsoidSurfaceAppearance, Ion, Material, Primitive, Rectangle, GeometryInstance, RectangleGeometry, createWorldTerrainAsync, ConstantPositionProperty, Cartesian3, Ellipsoid, Math as CesiumMath, KeyboardEventModifier, defined, ScreenSpaceEventType, ScreenSpaceEventHandler, UrlTemplateImageryProvider, CesiumTerrainProvider, CameraEventType, Entity, VerticalOrigin, HorizontalOrigin, HeightReference } from "cesium"
import { useCesiumGlobalStore } from "@/store/modules/cesiun-global"
import { load3dTileset } from "./3dTileset"
import { getAssetsFile } from "../common"
import { assert } from "console"

/**
 * 初始化cesium
 * @param container
 * @param options 
 * @param cb 
 * @returns 
 */
const initCesium = (container: string | HTMLDivElement, options?: Viewer.ConstructorOptions, cb?: Function): Viewer => {
  const defaultOptions = {
    geocoder: true, // 是否显示搜索按钮
    homeButton: true, // 是否显示主页按钮
    animation: false, // 是否显示左下角的仪表盘
    baseLayerPicker: false, // 是否显示图层选择器按钮，右上角那个地图图标
    fullscreenButton: false, // 是否显示全屏按钮
    sceneModePicker: false, // 是否显示右上角的模式切换按钮
    selectionIndicator: false, // 是否显示选取指示器组件
    timeline: false, // 是否显示下边的时间轴
    navigationHelpButton: false, // 是否显示右上角的帮助按钮
    vrButton: false, // 是否显示VR按钮
    infoBox: false, // 是否显示提示信息
    navigationInstructionsInitiallyVisible: true, // 是否显示导航
    scene3DOnly: true, // 是否指定仅为三维模式，全部使用三维模式可节约 GPU 资源
    requestRenderMode: false, // 启用请求渲染模式
    clampToGround: true,   //开启clampToGround属性绘制线，使其贴地
    requestWaterMask: true, // 请求水掩膜以实现水体效果
    requestVertexNormals: true, // 请求法线以实现光照效果
    contextOptions: {
      webgl: {
        preserveDrawingBuffer: true
      }
    },
    ...options
  }
  Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlNDJiNTA2MS02NTcwLTQyYzEtODVkMS1kMDdiOGYyZjZkZjUiLCJpZCI6MjU1MjUwLCJpYXQiOjE3MzYxMzEyMzR9.nZz7an2O3cVRL2fQl5BqgM5FT2ecaH1-YZnmU0c7DGQ';
  const viewer = new Viewer(container, defaultOptions);
  // 去除版权信息(隐藏Logo，水印)
  // @ts-ignore
  viewer.cesiumWidget.creditContainer.style.display = "none";
  viewer.scene.globe.depthTestAgainstTerrain = true; // 开启深度检测
  cb && cb()
  return viewer
}

/**
 * 添加自定义图层服务
 * @param viewer 
 * @param options
 */
const addImagery = (viewer: Viewer, options: UrlTemplateImageryProvider.ConstructorOptions) => {
  const imageryProvider = new UrlTemplateImageryProvider({
    ...options
  })
  viewer.imageryLayers.addImageryProvider(imageryProvider)
}

/**
 * 添加自定义地形服务
 */

const addTerrain = async (viewer: Viewer, source: string) => {
  const terrain: CesiumTerrainProvider = await CesiumTerrainProvider.fromUrl(source);
  viewer.terrainProvider = terrain;
};

/**
* 事件绑定
**/
const setInputActionEvent = (
  viewer: Viewer,
  callBack: Function,
  triggerType: ScreenSpaceEventType
) => {
  viewer.screenSpaceEventHandler.setInputAction((e: any) => {
    callBack(e);
  }, triggerType);
};

const setEventByHandler = (
  Handler: ScreenSpaceEventHandler,
  callBack: Function,
  triggerType: ScreenSpaceEventType
) => {
  Handler.setInputAction((e: any) => {
    callBack(e);
  }, triggerType);
};


/**
* 事件解绑
**/
const removeInputActionEvent = (
  viewer: Viewer,
  triggerType: ScreenSpaceEventType
) => {
  viewer.screenSpaceEventHandler.removeInputAction(triggerType);
};

const removeEventByHandler = (
  Handler: ScreenSpaceEventHandler,
  triggerType: ScreenSpaceEventType
) => {
  Handler.removeInputAction(triggerType);
};

/**
 * 清除Viewer上所有鼠标绑定事件
 */
const removeAllMouseEvent = (viewer: Viewer) => {
  for (let index = 0; index < 20; index++) {
    viewer.screenSpaceEventHandler.removeInputAction(index);
  }
}

/**
 * 清除指定事件句柄上所有鼠标绑定事件
 */
const removeAllHandlerMouseEvent = (
  Handler: ScreenSpaceEventHandler
) => {
  for (let index = 0; index < 20; index++) {
    Handler.removeInputAction(index);
  }
}


/**
 * 禁用相机控制
 */
const disableCameraControl = () => {
  const cesiumGlobalStore = useCesiumGlobalStore()
  const viewer = cesiumGlobalStore.getViewer()
  const controller = viewer.scene.screenSpaceCameraController;
  controller.enableRotate = false;
  controller.enableTranslate = false;
  controller.enableZoom = false;
  controller.enableTilt = false;
  controller.enableLook = false;
}

/**
 * 启用相机控制
 */
const enableCameraControl = () => {
  const cesiumGlobalStore = useCesiumGlobalStore()
  const viewer = cesiumGlobalStore.getViewer()
  const controller = viewer.scene.screenSpaceCameraController;
  controller.enableRotate = true;
  controller.enableTranslate = true;
  controller.enableZoom = true;
  controller.enableTilt = true;
  controller.enableLook = true;
}


/**
 * 相机自由姿态
 */
const freeCameraControl = () => {
  const cesiumGlobalStore = useCesiumGlobalStore()
  const viewer = cesiumGlobalStore.getViewer()
  const controller = viewer.scene.screenSpaceCameraController;
  controller.enableRotate = false;
  controller.enableTranslate = false;
  controller.enableZoom = false;
  controller.enableTilt = true;
  controller.enableLook = false;
  controller.tiltEventTypes = CameraEventType.LEFT_DRAG;
}

/**
 * 解除相机自由姿态(包含恢复所有交互)
 */
const fixedFreeCameraControl = () => {
  const cesiumGlobalStore = useCesiumGlobalStore()
  const viewer = cesiumGlobalStore.getViewer()
  const controller = viewer.scene.screenSpaceCameraController;
  controller.enableRotate = true;
  controller.enableTranslate = true;
  controller.enableZoom = true;
  controller.enableTilt = true;
  controller.enableLook = true;
  controller.tiltEventTypes = [
    CameraEventType.MIDDLE_DRAG,
    CameraEventType.PINCH,
    { eventType: CameraEventType.LEFT_DRAG, modifier: KeyboardEventModifier.CTRL },
    { eventType: CameraEventType.RIGHT_DRAG, modifier: KeyboardEventModifier.CTRL }
  ]
}

/**
 * 将rgba string类型颜色转换成cesium需要的颜色形式
 */
const rgbaStringToCesiumColor = (rgbaString: Color | string, opacity?: number) => {
  if (defined(rgbaString) && (rgbaString instanceof Color)) {
    return rgbaString;
  } else if (typeof rgbaString === "string") {
    if (rgbaString.includes("#")) { // '#ffffff' 形式
      const bigint = parseInt(rgbaString.slice(1), 16);
      const r = ((bigint >> 16) & 255) / 255;
      const g = ((bigint >> 8) & 255 / 255);
      const b = (bigint & 255) / 255;
      return new Color(r, g, b, opacity || 1);
    } else if (rgbaString.includes("rgb")) {
      const rgbaComponents = rgbaString.substring(5, rgbaString.length - 1).split(",");
      if (Array.isArray(rgbaComponents) && rgbaComponents.length >= 3) {
        const red = parseFloat(rgbaComponents[0].trim()) / 255.0;
        const green = parseFloat(rgbaComponents[1].trim()) / 255.0;
        const blue = parseFloat(rgbaComponents[2].trim()) / 255.0;
        const alpha = parseFloat(rgbaComponents[3]?.trim()) || opacity || 1;
        return new Color(red, green, blue, alpha);
      }
    }

    return Color.fromCssColorString(rgbaString) || Color.WHITE;
  }
  return Color.WHITE;
};


/**
 * 转换为cesium PositionProperty
 */
const transConstantPositionProperty = (value?: Cartesian3 | undefined) => {
  return new ConstantPositionProperty(value);
};

/**
 * 坐标转换 笛卡尔转84
 * @param {object} cartesian - 笛卡尔坐标
 * @returns {object} - {lng, lat, alt} - 地理坐标
 */
type Degree = {
  lng: number;
  lat: number;
  alt: number;
};
const transformCartesianToWGS84 = (cartesian: Cartesian3): Degree => {
  let ellipsoid = Ellipsoid.WGS84;
  let cartographic = ellipsoid.cartesianToCartographic(cartesian);
  return {
    lng: CesiumMath.toDegrees(cartographic.longitude),
    lat: CesiumMath.toDegrees(cartographic.latitude),
    alt: cartographic.height,
  };
};

/**
 * 获取当前cesium界面截图
 */
const getCesiumScreenshot = (viewer: Viewer): Promise<string> => {
  return new Promise((resolve, reject) => {
    try {
      const canvas = viewer.canvas;
      const imageData = canvas.toDataURL('image/png', 1.0);
      resolve(imageData);
    } catch (error) {
      console.error('截图失败:', error);
      reject(error);
    }
  });
}


/**
 * 自定义飞行动画
 */
const customFlyTo = (viewer: Viewer, options: {
  destination: Cartesian3;
  orientation?: {
    heading: number;
    pitch: number;
    roll: number;
  };
  duration: number;
  onComplete?: () => void;
  onCancel?: () => void;
}) => {
  const startPosition = viewer.camera.position.clone();
  const startTime = performance.now();
  let frame: number;
  const cesiumGlobalStore = useCesiumGlobalStore();

  // 使用 easeInOutCubic 缓动函数
  const easeInOutCubic = (t: number) => {
    return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
  };

  const animate = (currentTime: number) => {
    cesiumGlobalStore.flyType === 'fixed' ? disableCameraControl() : freeCameraControl();
    const elapsed = currentTime - startTime; // 计算已经过去的时间
    const t = Math.min(elapsed / (options.duration * 1000), 1.0); // 计算当前时间占总时间的比例
    const easedT = easeInOutCubic(t);
    // 计算当前位置
    const currentPosition = new Cartesian3(
      startPosition.x + (options.destination.x - startPosition.x) * easedT,
      startPosition.y + (options.destination.y - startPosition.y) * easedT,
      startPosition.z + (options.destination.z - startPosition.z) * easedT
    );

    if (cesiumGlobalStore.flyType === 'fixed') {
      // 固定模式：更新位置和方向
      viewer.camera.setView({
        destination: currentPosition,
        orientation: options.orientation
      });
    } else {
      // 自由模式：只更新位置，保持当前视角
      const currentHeading = viewer.camera.heading;
      const currentPitch = viewer.camera.pitch;
      const currentRoll = viewer.camera.roll;

      viewer.camera.setView({
        destination: currentPosition,
        orientation: {
          heading: currentHeading,
          pitch: currentPitch,
          roll: currentRoll
        }
      });
    }

    if (t < 1.0) {
      frame = requestAnimationFrame(animate);
    } else {
      options.onComplete?.();
    }
  };

  frame = requestAnimationFrame(animate);

  // 返回取消函数
  return () => {
    cancelAnimationFrame(frame);
    options.onCancel?.();
  };
};

/**
 * 设置鼠标长按事件和图标
 */
const setMouseLongPressIcon = (viewer: Viewer, options: {
  leftButton?: {
    cursor: string;
    pressTime?: number;
  };
  middleButton?: {
    pressTime?: number;
    iconUrl?: string;
    iconSize?: {
      width: number;
      height: number;
    };
  };
}) => {
  let leftPressTimer: NodeJS.Timeout | null = null;
  let middlePressTimer: NodeJS.Timeout | null = null;
  const canvas = viewer.canvas;
  const originalCursor = canvas.style.cursor;
  let billboardEntity: Entity | null = null;

  // 左键按下
  setInputActionEvent(viewer, () => {
    leftPressTimer = setTimeout(() => {
      canvas.style.cursor = options.leftButton!.cursor;
    }, options.leftButton?.pressTime || 500);
  }, ScreenSpaceEventType.LEFT_DOWN);

  // 中键按下
  setInputActionEvent(viewer, (movement: any) => {
    const cartesian = viewer.scene.pickPosition(movement.position);
    if (!cartesian) return;

    middlePressTimer = setTimeout(() => {
      canvas.style.cursor = 'none';
      // 创建广告牌实体
      billboardEntity = viewer.entities.add({
        position: cartesian,
        billboard: {
          image: getAssetsFile(options.middleButton?.iconUrl || ''),
          width: options.middleButton?.iconSize?.width || 64,
          height: options.middleButton?.iconSize?.height || 64,
          verticalOrigin: VerticalOrigin.CENTER,
          horizontalOrigin: HorizontalOrigin.CENTER,
          // heightReference: HeightReference.CLAMP_TO_GROUND,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
          color: Color.WHITE
        }
      });
    }, options.middleButton?.pressTime || 500);
  }, ScreenSpaceEventType.MIDDLE_DOWN);

  // 中键抬起
  setInputActionEvent(viewer, () => {
    if (middlePressTimer) {
      clearTimeout(middlePressTimer);
      middlePressTimer = null;
      canvas.style.cursor = originalCursor;
      if (billboardEntity) {
        viewer.entities.remove(billboardEntity);
        billboardEntity = null;
      }
    }
  }, ScreenSpaceEventType.MIDDLE_UP);

  // 左键抬起
  setInputActionEvent(viewer, () => {
    canvas.style.cursor = originalCursor
  }, ScreenSpaceEventType.LEFT_UP);

  // 返回清理函数
  return () => {
    removeAllMouseEvent(viewer);
    canvas.style.cursor = originalCursor;
    if (leftPressTimer) clearTimeout(leftPressTimer);
    if (middlePressTimer) clearTimeout(middlePressTimer);
    if (billboardEntity) {
      viewer.entities.remove(billboardEntity);
    }
  };
};


/**
 * 全球水域效果
 */
const addEarthWater = (viewer: Viewer) => {
  viewer.scene.primitives.add(new Primitive({
    geometryInstances: new GeometryInstance({
      geometry: new RectangleGeometry({
        rectangle: Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
        vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT
      })
    }),
    //水材质
    appearance: new EllipsoidSurfaceAppearance({
      material: new Material({
        fabric: {
          type: 'Water',
          uniforms: {
            // 水区颜色
            baseWaterColor: new Color(89 / 255, 148 / 255, 236 / 255, 1),
            // 从水区到非水区域混合
            blendColor: new Color(0.5, 1.0, 0.699, 1.0),
            normalMap: getAssetsFile("cesium/waterNormals.jpg"),
            specularMap: getAssetsFile("cesium/earth.jpg"),
            frequency: 2000.0,  // 波浪数量。
            animationSpeed: 0.01, // 动画速度
            amplitude: 10.0,    // 水波振幅
            specularIntensity: 0,   // 镜面反射强度
          }
        }
      }),
      aboveGround: true
    }),
    show: true
  }))
}


export {
  initCesium,
  addImagery,
  addTerrain,
  setInputActionEvent,
  setEventByHandler,
  removeInputActionEvent,
  removeEventByHandler,
  removeAllMouseEvent,
  removeAllHandlerMouseEvent,
  disableCameraControl,
  enableCameraControl,
  freeCameraControl,
  fixedFreeCameraControl,
  rgbaStringToCesiumColor,
  transConstantPositionProperty,
  getCesiumScreenshot,
  customFlyTo,
  setMouseLongPressIcon,
  transformCartesianToWGS84,
  addEarthWater,

  // 3dTileset
  load3dTileset,
}
